package com.romanito.andiview;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast;
import android.widget.ViewFlipper;
import android.widget.ImageView.ScaleType;

public class Andiview extends Activity {

	static public final String DEBUG_TAG = "Andiview";

	// Widgets
	private ImageView _ivVisible, _ivNext, _ivPrevious;
	private ViewFlipper _flipper;

	// Other fields
	private ImageNavigator _imageNav;
	private volatile ImageLoadThreadGroup _imageLoadThreadGroup;
	private boolean _firstDisplay;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		_flipper = (ViewFlipper) findViewById(R.id.flipper);
		_flipper.setOnTouchListener(flipper_OnTouch);

		_ivPrevious = new ImageView(this);
		_flipper.addView(_ivPrevious);
		_ivVisible = new ImageView(this);
		_flipper.addView(_ivVisible);
		_ivNext = new ImageView(this);
		_flipper.addView(_ivNext);

		_imageNav = new ImageNavigator(getIntent().getData());

		_imageLoadThreadGroup = new ImageLoadThreadGroup();

		Preferences.load(this);

		_firstDisplay = true;
		displayFirstImage();

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.options, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_preferences:
			startActivity(new Intent(this, Preferences.class));
			Preferences.load(this);
			return true;
		case R.id.menu_share:
			shareImage();
			return true;
		case R.id.menu_set_as:
			setAsImage();
			return true;
		case R.id.menu_details:
			showDetails();
			return true;
		}
		return false;
	}

	// Points ImageViews to the corresponding variables
	private void getImageViews() {
		int i = _flipper.getDisplayedChild();
		_ivVisible = (ImageView) _flipper.getChildAt(i);
		if (++i >= _flipper.getChildCount())
			i = 0;
		_ivNext = (ImageView) _flipper.getChildAt(i);
		if (++i >= _flipper.getChildCount())
			i = 0;
		_ivPrevious = (ImageView) _flipper.getChildAt(i);
	}

	// Displays the first image
	private void displayFirstImage() {
		getImageViews();
		loadImageInView(_ivVisible, _imageNav.getCurrentImageFile().getFullName(), true);
	}

	// Displays the next image in the list
	private void displayNextImage() {
		if (Preferences.getTransitions().equals("slide")) {
			_flipper.setInAnimation(this, R.anim.slide_left_in);
			_flipper.setOutAnimation(this, R.anim.slide_right_out);
		} else {
			_flipper.setInAnimation(null);
			_flipper.setOutAnimation(null);
		}
		_flipper.showNext();
		getImageViews();
		_imageNav.goToNextImage();

		loadImageInView(_ivNext, _imageNav.getNextImageFile().getFullName(), false);
	}

	// Displays the previous image in the list
	private void displayPreviousImage() {
		if (Preferences.getTransitions().equals("slide")) {
			_flipper.setInAnimation(this, R.anim.slide_right_in);
			_flipper.setOutAnimation(this, R.anim.slide_left_out);
		} else {
			_flipper.setInAnimation(null);
			_flipper.setOutAnimation(null);
		}
		_flipper.showPrevious();
		getImageViews();
		_imageNav.goToPreviousImage();

		loadImageInView(_ivPrevious, _imageNav.getPreviousImageFile().getFullName(), false);
	}

	private void loadImageInView(ImageView imageView, String imageUri, boolean highPriority) {

		// No more than 3 threads at a time
		if (_imageLoadThreadGroup.activeCount() >= 3)
			_imageLoadThreadGroup.stopOldestThread();

		// "Loading" image
		imageView.setScaleType(ScaleType.CENTER);
		imageView.setImageResource(android.R.drawable.ic_menu_gallery);

		// Load actual image in a separate thread
		ImageLoadThread ilt = new ImageLoadThread(imageView, imageUri);
		if (highPriority)
			ilt.setPriority(Thread.MAX_PRIORITY);
		ilt.start();

	}

	// Called when an image has been loaded
	private void imageLoaded(ImageView imageView, Bitmap bitmap) {

		if (bitmap == null) {
			Toast.makeText(this, "Picture '" + _imageNav.getCurrentImageFile().getName() + "' could not be decoded.", Toast.LENGTH_LONG).show();
			return;
		}

		imageView.setImageBitmap(bitmap);
		imageView.invalidate();
		if (_firstDisplay) {
			if (imageView == _ivVisible)
				loadImageInView(_ivNext, _imageNav.getNextImageFile().getFullName(), false);
			else {
				loadImageInView(_ivPrevious, _imageNav.getPreviousImageFile().getFullName(), false);
				_firstDisplay = false;
			}
		}
	}

	private class ImageLoadThread extends Thread {
		private ImageView _imageView;
		private String _imageUri;
		private long _startTime;
		private boolean _stopRequested;
		private BitmapFactory.Options _bitmapOptions;

		public ImageLoadThread(ImageView imageView, String imageUri) {
			super(_imageLoadThreadGroup, "Image load");
			_imageView = imageView;
			_imageUri = imageUri;
			_stopRequested = false;
		}

		@Override
		public void run() {
			_startTime = System.currentTimeMillis();

			_bitmapOptions = new BitmapFactory.Options();
			_bitmapOptions.inSampleSize = 1;

			boolean LoadOK = false;

			System.gc();
			while (!LoadOK) {
				try {
					if (_stopRequested)
						return;

					final Bitmap bmp = BitmapFactory.decodeFile(_imageUri, _bitmapOptions);

					if (_stopRequested)
						return;

					runOnUiThread(new Runnable() {
						@Override
						public void run() {
							imageLoaded(_imageView, bmp);
						}
					});

					LoadOK = true;
				} catch (OutOfMemoryError e) {
					yield();
					System.gc();
					_bitmapOptions.inSampleSize += 1;
				}
			}
			super.run();
		}

		public long getStartTime() {
			return _startTime;
		}

		public void requestStop() {
			_stopRequested = true;
			if (_bitmapOptions != null)
				_bitmapOptions.requestCancelDecode();
		}
	}

	private class ImageLoadThreadGroup extends ThreadGroup {

		public ImageLoadThreadGroup() {
			super("Image load thread group");
		}

		public void stopOldestThread() {
			long oldestTime = System.currentTimeMillis();
			int oldestThreadIndex = -1;

			ImageLoadThread activeThreads[] = new ImageLoadThread[this.activeCount()];
			this.enumerate(activeThreads);

			for (int i = 0; i < activeThreads.length; i++) {
				if (activeThreads[i].getPriority() < Thread.MAX_PRIORITY && activeThreads[i].getStartTime() < oldestTime) {
					oldestTime = activeThreads[i].getStartTime();
					oldestThreadIndex = i;
				}
			}

			if (oldestThreadIndex > -1)
				activeThreads[oldestThreadIndex].requestStop();
		}

	}

	private OnTouchListener flipper_OnTouch = new OnTouchListener() {

		private float _actionTouchDownX, _actionTouchDownY, _actionTouchMoveY;

		@Override
		public boolean onTouch(View v, MotionEvent event) {

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				_actionTouchDownX = event.getX();
				_actionTouchDownY = _actionTouchMoveY = event.getY();
				break;
			case MotionEvent.ACTION_MOVE:
				// If the vertical delta is greater than the horizontal one,
				// initiate zooming
				if (Math.abs(_actionTouchDownX - event.getX()) < Math.abs(_actionTouchDownY - event.getY())) {
					_ivVisible.zoomBy((_actionTouchMoveY - event.getY()) / 100);
					_actionTouchMoveY = event.getY();
				}
				break;
			case MotionEvent.ACTION_UP:
				// If the horizontal delta is greater than the vertical one,
				// move to next image
				if (Math.abs(_actionTouchDownX - event.getX()) > Math.abs(_actionTouchDownY - event.getY())) {
					if (event.getX() < _actionTouchDownX) {
						displayNextImage();
					} else {
						displayPreviousImage();
					}
				}
				break;
			}

			return true;
		}
	};

	@Override
	public boolean onTrackballEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE:
			_ivVisible.panBy(Preferences.getInvertPanning() * event.getX(), Preferences.getInvertPanning() * event.getY());
			break;
		}
		return super.onTrackballEvent(event);
	}

	private void shareImage() {
		// Intent for sending the image
		Intent sendIntent = new Intent(Intent.ACTION_SEND);
		sendIntent.putExtra(Intent.EXTRA_STREAM, _imageNav.getCurrentImageFile().getUri());
		sendIntent.setType(_imageNav.getCurrentImageFile().getMimeType());
		// Display an action chooser
		try {
			startActivity(Intent.createChooser(sendIntent, getText(R.string.send_image)));
		} catch (android.content.ActivityNotFoundException ex) {
			Toast.makeText(this, R.string.no_way_to_share_image, Toast.LENGTH_SHORT).show();
		}
	}
	
	private void setAsImage() {
		// Intent for setting the image
		Intent setAsIntent = new Intent(Intent.ACTION_ATTACH_DATA);
		setAsIntent.setDataAndType(_imageNav.getCurrentImageFile().getUri(), _imageNav.getCurrentImageFile().getMimeType());
		setAsIntent.putExtra("mimeType", _imageNav.getCurrentImageFile().getMimeType());
		// Display an action chooser
		try {
			startActivity(Intent.createChooser(setAsIntent, getText(R.string.set_image)));
		} catch (android.content.ActivityNotFoundException ex) {
			Toast.makeText(this, R.string.no_way_to_set_image, Toast.LENGTH_SHORT).show();
		}
	}
	
	private void showDetails() {		
		ImageFile img = _imageNav.getCurrentImageFile();
		String msg = "";
		msg += "Dimensions: " + _ivVisible.getBitmapWidth() + "x" + _ivVisible.getBitmapHeight() + "\n";
		msg += "MIME type: " + img.getMimeType();
		
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(msg)
			   .setTitle(img.getName());
		       //.setIcon(_ivVisible.getDrawable());
		builder.create().show();
	}
}